react code-split

在 google 跑分時總是會出現,xxx.chunk.js 太肥囉,要該減肥一下呦,順便去除沒有用到的東西

然後基於你是 react 框架,如果不使用 SSR 推薦你使用 React.lazy() 或是處理 code-split 可以使用 loadable-components

google-shootcut

好,所以我們的目標是把大大的 main.xxx.chunk.js code-split 拆分掉


react bundle analyzer

source-map-explorer

在處理 bundle 之前,先安裝可以看清楚 bundle 畫面的 package create-react-app 官方(Analyzing the Bundle Size)是用 source-map-explorer

在外面看到大部分人都用 webpack-bundle-analyzer 但這篇文章(Revisit the decision to allow webpack analyzer tools)似乎是有說他有標籤標記錯誤的問題,但是裡面也有很多人舉例說為啥他會愛 webpack-bundle-analyzer 勝過於 source-map-explorer 的原因 😂

$npm i -D source-map-explorer

package.json 新增一條 script

//package.json
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
}

在執行 build 跟 analyze

$npm run build
$npm run analyze

也可以改寫成這樣

"analyze": "npm run build && npm run analyze-bundle",
"analyze-bundle": "source-map-explorer 'build/static/js/*.js'"

這樣只要跑一行指令就好了

$npm run analyze

source-map-explorer

webpack-bundle-analyzer

不 eject CRA 狀態下用 webpack-bundle-analyzer

$npm i -D webpack-bundle-analyzer
//package.json
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build --stats && webpack-bundle-analyzer build/bundle-stats.json -m static -r build/bundle-stats.html -O",
"test": "react-scripts test"
}
}

測試了很久都沒有成功,後來找到文件說

Using webpack-bundle-analyzer has been deprecated an the flag `—-stats` has been removed in CRA v3. You should be using source-map-explorer instead by running: `npm i -g source-map-explorer`and `source-map-explorer 'build/static/js/*.js'`.
The following paragraph is deprecated:

原本可以用 --stats 來生出 bundle-stats.json 但看起來 CRA 就是要推廣 source-map-explorer 整個拿掉沒辦法在不 eject 狀態下用惹QQ


react-loadable

react 在做 code-split 也可以針對 react-router 做處理

react-router 官方文件是推薦使用 loadable-component 但看仿間大多人都使用 react-loadable

$npm i react-loadable
import Loadable from "react-loadable";
import Loading from "./my-loading-component";

const LoadableComponent = Loadable({
loader: () => import("./my-component"),
loading: Loading,
});

export default class App extends React.Component {
render() {
return <LoadableComponent />;
}
}

Dynamic imports 寫法

這邊預設 function 是 export default ,但我通常都只有 export const 所以這邊 import 要改寫成

const LoadableComponent = Loadable({
loader: () => import("./my-component").then(({ Component }) => Component),
loading: Loading,
});

但測試後發現,怎麼 chunck 沒有分開?!!原因是因為我都在同一個 index.js 通通 export 所以他一樣會包在一起

發現這篇文章也有一樣的問題 Code splitting with create-react-app and react-loadable is not working

pages-index

因為在該 index.js 頁面就已經全部都合在一起了,所以要把這邊 index.js mark 掉,然後 import 分開寫,如果 index.js 沒有 mark 掉,即使引入分開寫,也一樣會包在一起不會分開歐

named chunks.js

如果想要 name chunks.js 檔案的話,可以這樣做設定

const Policies = Loadable({
loading: PageLoading,
loader: () =>
import(
/* webpackChunkName: "policies" */
"pages/Policies"
).then((module) => module.Policies),
});

原本是 2.chunk.js 就會命名稱 policies.chunk.js

no-webpackChunkNameuse-webpackChunkName

create-react-app 的 webpack 有設定這功能,如果沒有反應的話要去 wepback 的 config 檔,新增下面的設定

output: {
path: path.join(__dirname, './../public'),
filename: 'bundle.js',
publicPath: '/',
chunkFilename: '[name].[chunkhash].js'
},

result

原本 main chunk 427.04 kb 占 38%

code-split 後 342.34kb 占 27.3%

originorigin

afterafter code-split


React.lazy

react Code-Splitting

如果只用 react 原生的 lazy 也可以達到 code-split 的效果

import React, { Suspense, lazy } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import { Home } from "./components/Home";

export const Routes = () => {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route
path="/about"
component={lazy(() =>
import(/* webpackChunkName: "about" */ "./components/About")
)}
/>
<Route path="/" component={Home} />
</Switch>
</Suspense>
</Router>
);
};

trouble shooting

用 react lazy 的話,他只接受 const MyComponent = lazy(() => import('./MyComponent')) 的格式

react.lazy-err

所以要 export default

export const About = () => {
return (
<div>
About<Link to="/">Home</Link>
</div>
);
};

⭕️

let About;
export default About = () => {
return (
<div>
About<Link to="/">Home</Link>
</div>
);
};

[reference]


把已開發好的專案新增 code-split 真的比一開始開發就加上去來的還有跳戰性啊~!!